package com.hyzh.latte.util.gather;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.hyzh.latte.vehicle.dmo.PersonGatherDTO;
import com.hyzh.latte.vehicle.dmo.PersonTrackDTO;
import com.hyzh.latte.vehicle.dmo.entity.ParkPGEntity;
import lombok.extern.slf4j.Slf4j;
import smile.clustering.DBSCAN;
import smile.math.distance.EuclideanDistance;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class GatherUtils {

    public static Set<Point> detectGatheringPoint(List<Point> locations, int num, double rad) {
        Set<Point> personLocations = new HashSet<>();
        double[][] locationsArray = locations.stream()
                .map(location -> new double[]{location.getLat(), location.getLon()})
                .toArray(double[][]::new);
        DBSCAN<double[]> dbscan = DBSCAN.fit(locationsArray, new EuclideanDistance(), num, rad);
        int numClusters = (int) Arrays.stream(dbscan.y).filter(clusterId -> clusterId != -1).distinct().count();
        for (int i = 0; i < numClusters; i++) {
            int finalI = i;
            List<Point> cluster = locations.stream()
                    .filter(location -> dbscan.predict(new double[]{location.getLat(), location.getLon()}) == finalI)
                    .collect(Collectors.toList());
            Point center = calculateCenter(cluster);
            if (center.getLon() > 0) {
                personLocations.add(center);
//              System.out.println("聚集点" + (i + 1) + "的中心经度: " + center.getLon() + ", 纬度: " + center.getLat() + ", 人数: " + cluster.size());
            }
        }
        return personLocations;
    }

    private static Point calculateCenter(List<Point> locations) {
        double sumLat = 0.0;
        double sumLon = 0.0;
        for (Point location : locations) {
            sumLat += location.getLat();
            sumLon += location.getLon();
        }
        return new Point(sumLat / locations.size(), sumLon / locations.size());
    }

    public static List<PersonGatherDTO> buildGatherDto(Collection<PersonTrackDTO> personTrackRecord, ParkPGEntity parkPGEntity){
        if (CollectionUtil.isEmpty(personTrackRecord) || null == parkPGEntity.getGatherNumber() || parkPGEntity.getGatherNumber() == 0 || personTrackRecord.size() < parkPGEntity.getGatherNumber()){
            log.info("--personTrackRecord- is null or size < number; size: {} ----park: {}--", CollectionUtil.isEmpty(personTrackRecord) ? 0 : personTrackRecord.size(),  parkPGEntity.getParkCode());
            return new ArrayList<>();
        }
        log.info("--PersonTrackDTO--{}-", JSON.toJSONString(personTrackRecord));
        List<Point> locations = personTrackRecord.stream().map(PersonTrackDTO::buildPoint).collect(Collectors.toList());
        log.info("---point-{}--", JSON.toJSONString(locations));
        Set<Point> set = detectGatheringPoint(locations, parkPGEntity.getGatherNumber()-1, (double) parkPGEntity.getGatherRad() /1000);
        if (CollectionUtil.isEmpty(set)){
            return new ArrayList<>();
        }
        return set.stream().map(x -> x.buildDTO(parkPGEntity.getGatherNumber())).collect(Collectors.toList());
    }

/*

    public static void main(String[] args) throws InterruptedException {
        List<PersonTrackDTO> list = new ArrayList<>();
        ParkPGEntity pgEntity = new ParkPGEntity();
        pgEntity.setGatherRad(3);
        pgEntity.setGatherNumber(3);
        double RADIUS = (double)pgEntity.getGatherRad()/1000;
        //聚集点1
        for (int i = 0; i < 3; i++) {
            double[] doubles = generateRandomPoint(39.9087d, 116.3975d, RADIUS);
            list.add(new PersonTrackDTO(doubles[0], doubles[1]));
        }
//        //聚集点2
        for (int i = 0; i < 2; i++) {
            double[] doubles = generateRandomPoint(36.9087d, 112.3975d, RADIUS);
            list.add(new PersonTrackDTO(doubles[0], doubles[1]));
        }

        //聚集点3
        for (int i = 0; i < 3; i++) {
            double[] doubles = generateRandomPoint(38.9087d, 114.3975d, RADIUS);
            list.add(new PersonTrackDTO(doubles[0], doubles[1]));
        }


        Collections.shuffle(list);

        List<PersonGatherDTO> pl = buildGatherDto(list, pgEntity);
//        Set<Point> personLocations = detectGatheringPoint(list, 6, RADIUS);
        System.out.println(pl.size() + "***********"+ JSON.toJSONString(pl));
    }

    private static final double EARTH_RADIUS = 6371000; // 地球半径，单位为米

    private static double[] generateRandomPoint(double centerLat, double centerLon, double radiusInMeters) {
        Random random = new Random();

        // Convert radius from meters to degrees
        double radiusInDegrees = radiusInMeters / EARTH_RADIUS;

        // Random angle
        double angle = random.nextDouble() * Math.PI * 2;

        // Random distance
        double distance = random.nextDouble() * radiusInDegrees;

        // Calculate random point's lat and lon
        double randomLat = centerLat + Math.toDegrees(distance * Math.cos(angle));
        double randomLon = centerLon + Math.toDegrees(distance * Math.sin(angle)) / Math.cos(Math.toRadians(centerLat));

        return new double[]{randomLat, randomLon};
    }*/
}




